/**
	Pulsar engine. Core.
	Source file. String operations: advanced formatting

	Copyright (C) 2013-2014 Dmitry Dolgov

	This program is free software; you can redistribute it and/or modify it under the terms of the
	GNU General Public License as published by the Free Software Foundation; either version 2 of
	the License, or (at your option) any later version.
		
	This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
	without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
	See the GNU General Public License for more details.
*/

#include <pulsar/pulsar.h>

namespace pl
{

static void _extractOptions(const pl_char* str, const pl_char* end, _Options& opt);
static _Align _getAlign(const pl_char* str, const pl_char** end);

} // namespace pl

/**
*/
pl_uint32 pl::_findSubst(const pl_char* str, pl_uint32 pos, _Options& opt, pl_uint32& replacement)
{
	pl_uint32 i;

	// Fill by default
	opt.align = _ALIGN_LEFT;
	opt.fillChar = 0;
	opt.size = 0;
	opt.decPoint = 0;
	opt.radix = 10;

	for (i=0; str[i] != PL_T('\0'); i++)
	{
		if (str[i] != PL_T('%'))
		{
			continue;
		}

		if (str[i+1] != PL_T('%'))
		{
			continue;
		}
		// May be "%%num"
		// or "%%[options]num"
		if (str[i+2] == (pl_char)(pos + PL_T('0')))
		{
			replacement = 3; // Change %%# with actual data
			return i;
		}
		else if (str[i+2] == PL_T('['))
		{
			const pl_char* end = pl_strchr(str + i, PL_T(']'));
			if (end == NULL)
			{
				// Bad syntax, ignore
				continue;
			}
			if (end[1] != (pl_char)(pos + PL_T('0')))
			{
				// Wrong argument, ignore
				continue;
			}

			// Analyze content and translate it to options
			_extractOptions(str+i+3, end-1, opt);
			replacement = (pl_uint32)(end - str) + i;
			return i;
		}
	}

	// Not found
	return i;
}

/**
*/
static void pl::_extractOptions(const pl_char* str, const pl_char* end, _Options& opt)
{
	while (str < end)
	{
		if (pl_strncmp(str, PL_T("size"), 4) == 0)
		{
			PL_ASSERTW(str[4] == PL_T(':'), PL_T("Bad formatting options"));
			opt.size = pl::str2num<pl_uint16>(str+5, &str);
		}
		else if (pl_strncmp(str, PL_T("align"), 5) == 0)
		{
			PL_ASSERTW(str[5] == PL_T(':'), PL_T("Bad formatting options"));
			opt.align = (pl_uint8)_getAlign(str+6, &str);
		}
		else if (pl_strncmp(str, PL_T("fill"), 4) == 0)
		{
			PL_ASSERTW(str[4] == PL_T(':'), PL_T("Bad formatting options"));
			opt.fillChar = str[5];
			str += 6;
		}
		else if (pl_strncmp(str, PL_T("dec"), 3) == 0)
		{
			PL_ASSERTW(str[3] == PL_T(':'), PL_T("Bad formatting options"));
			opt.decPoint = pl::str2num<pl_uint8>(str+4, &str);
		}
		else if (pl_strncmp(str, PL_T("radix"), 5) == 0)
		{
			PL_ASSERTW(str[5] == PL_T(':'), PL_T("Bad formatting options"));
			opt.radix = pl::str2num<pl_uint8>(str+6, &str);
		}
		else
		{
			// Bad option - stop handling
			PL_ASSERTW(FALSE, PL_T("Bad formatting options"));
			return;
		}
		PL_ASSERTW(*str == PL_T(',') || *str == PL_T(']'), PL_T("Bad formatting options"));
		str++;
	}
	return;
}

static pl::_Align pl::_getAlign(const pl_char* str, const pl_char** end)
{
	if (pl_strncmp(str, PL_T("left"), 4) == 0)
	{
		*end = str + 4;
		return _ALIGN_LEFT;
	}
	if (pl_strncmp(str, PL_T("right"), 5) == 0)
	{
		*end = str + 5;
		return _ALIGN_RIGHT;
	}
	if (pl_strncmp(str, PL_T("center"), 6) == 0)
	{
		*end = str + 6;
		return _ALIGN_CENTER;
	}
	PL_ASSERTW(FALSE, PL_T("Bad formatting options"));
	return _ALIGN_LEFT;
}

//
// End of file 'pulsar_string_format'
//
